<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>🌲 Spring | Xiangyu&#39;s Blog</title>
    <meta name="generator" content="VuePress 1.8.2">
    <script src="https://cdn.jsdelivr.net/npm/react/umd/react.production.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/react-dom/umd/react-dom.production.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@babel/standalone/babel.min.js"></script>
    <link rel="alternate" type="application/atom+xml" href="https://blog.lixiangyu.xyz/atom.xml" title="Xiangyu&#39;s Blog Atom Feed">
    <link rel="alternate" type="application/json" href="https://blog.lixiangyu.xyz/feed.json" title="Xiangyu&#39;s Blog JSON Feed">
    <link rel="alternate" type="application/rss+xml" href="https://blog.lixiangyu.xyz/rss.xml" title="Xiangyu&#39;s Blog RSS Feed">
    <meta name="description" content="">
    <meta property="og:url" content="/interview/framework/spring/spring.html">
    <meta property="og:site_name" content="Xiangyu's Blog">
    <meta property="og:title" content="🌲 Spring">
    <meta property="og:type" content="article">
    <meta property="og:locale" content="zh-CN">
    <meta name="twitter:card" content="summary_large_image">
    <meta name="twitter:image:alt" content="Xiangyu's Blog">
    <meta property="article:author" content="Xiangyu Li">
    
    <link rel="preload" href="/assets/css/0.styles.79654418.css" as="style"><link rel="preload" href="/assets/js/app.a42375e9.js" as="script"><link rel="preload" href="/assets/js/vendors~layout-Layout.8269724e.js" as="script"><link rel="preload" href="/assets/js/vendors~layout-Blog~layout-Layout~layout-NotFound.43b0f70d.js" as="script"><link rel="preload" href="/assets/js/page-🌲Spring.bc450c2f.js" as="script"><link rel="preload" href="/assets/js/vendors~layout-Blog~layout-Layout~layout-NotFound~layout-Slide.99c28334.js" as="script"><link rel="prefetch" href="/assets/js/120.3fbfaa84.js"><link rel="prefetch" href="/assets/js/121.1b7d4f7b.js"><link rel="prefetch" href="/assets/js/122.beff33c9.js"><link rel="prefetch" href="/assets/js/123.b1ea2b2a.js"><link rel="prefetch" href="/assets/js/124.80db1ca6.js"><link rel="prefetch" href="/assets/js/layout-Blog.5897b816.js"><link rel="prefetch" href="/assets/js/layout-Layout.62afd99c.js"><link rel="prefetch" href="/assets/js/layout-NotFound.232bd0de.js"><link rel="prefetch" href="/assets/js/layout-Slide.3e86b53c.js"><link rel="prefetch" href="/assets/js/mermaid.efa5ef99.js"><link rel="prefetch" href="/assets/js/page-☀️类加载机制.e96f671b.js"><link rel="prefetch" href="/assets/js/page-☘️通讯组件-简介.4b81f185.js"><link rel="prefetch" href="/assets/js/page-♟️百度.c4749d47.js"><link rel="prefetch" href="/assets/js/page-⛈️Map接口-简介.3865d2e3.js"><link rel="prefetch" href="/assets/js/page-⛑️HTTPS协议.66168577.js"><link rel="prefetch" href="/assets/js/page-⛷️TreeSet.9d82d551.js"><link rel="prefetch" href="/assets/js/page-⛹️LinkedHashMap.a11fa0e5.js"><link rel="prefetch" href="/assets/js/page-✈️Kafka.02647d0b.js"><link rel="prefetch" href="/assets/js/page-✌️索引.8092b72a.js"><link rel="prefetch" href="/assets/js/page-⭐内存区域划分.b3f4a65e.js"><link rel="prefetch" href="/assets/js/page-主页.28a585f2.js"><link rel="prefetch" href="/assets/js/page-🌀JVM-简介.cbd691d7.js"><link rel="prefetch" href="/assets/js/page-🌀JavaIO-简介.8b218ef6.js"><link rel="prefetch" href="/assets/js/page-🌀Java基础-简介.3cff2536.js"><link rel="prefetch" href="/assets/js/page-🌀Java容器-简介.21a7bf8b.js"><link rel="prefetch" href="/assets/js/page-🌀Java并发-简介.a400b8d1.js"><link rel="prefetch" href="/assets/js/page-🌀MySQL-简介.61b33b6a.js"><link rel="prefetch" href="/assets/js/page-🌀Redis-简介.f815bad6.js"><link rel="prefetch" href="/assets/js/page-🌀中间件-简介.5640181c.js"><link rel="prefetch" href="/assets/js/page-🌀操作系统-简介.46e7356e.js"><link rel="prefetch" href="/assets/js/page-🌀框架使用-简介.3af4c120.js"><link rel="prefetch" href="/assets/js/page-🌀计算机网络-简介.23bd59fd.js"><link rel="prefetch" href="/assets/js/page-🌀设计思想-简介.0711e244.js"><link rel="prefetch" href="/assets/js/page-🌀面经.5cfe0142.js"><link rel="prefetch" href="/assets/js/page-🌙垃圾回收机制.db23d79a.js"><link rel="prefetch" href="/assets/js/page-🌧️Set接口-简介.d19cf767.js"><link rel="prefetch" href="/assets/js/page-🌩️List接口-简介.112f20b7.js"><link rel="prefetch" href="/assets/js/page-🌳SpringMVC.91b7e35a.js"><link rel="prefetch" href="/assets/js/page-🌴SpringBoot.ff4435cc.js"><link rel="prefetch" href="/assets/js/page-🌵SpringCloud.61f20500.js"><link rel="prefetch" href="/assets/js/page-🌻MyBatis.2d99e7fc.js"><link rel="prefetch" href="/assets/js/page-🌼MyBatis框架-简介.66f9a744.js"><link rel="prefetch" href="/assets/js/page-🍀Netty.54e2d65a.js"><link rel="prefetch" href="/assets/js/page-🍁Dubbo.66727d8a.js"><link rel="prefetch" href="/assets/js/page-🎧学堂在线.81d9ee7e.js"><link rel="prefetch" href="/assets/js/page-🎭Boss直聘.14beba08.js"><link rel="prefetch" href="/assets/js/page-🎱老虎集团.fc8b12ba.js"><link rel="prefetch" href="/assets/js/page-🎲字节跳动.5676ea28.js"><link rel="prefetch" href="/assets/js/page-🎺猿辅导.7520f1e7.js"><link rel="prefetch" href="/assets/js/page-🏄LinkedHashSet.2e22c9f1.js"><link rel="prefetch" href="/assets/js/page-🏌️HashSet.820baa69.js"><link rel="prefetch" href="/assets/js/page-🐒锁.868714d5.js"><link rel="prefetch" href="/assets/js/page-🐵JUC.9672a0f1.js"><link rel="prefetch" href="/assets/js/page-👂视图.f277e783.js"><link rel="prefetch" href="/assets/js/page-👋数据类型.b99f167f.js"><link rel="prefetch" href="/assets/js/page-👍事务.ef00d241.js"><link rel="prefetch" href="/assets/js/page-👎慢查询.a1afcd91.js"><link rel="prefetch" href="/assets/js/page-👓IP地址.f0579df2.js"><link rel="prefetch" href="/assets/js/page-👕其他.647a9b2f.js"><link rel="prefetch" href="/assets/js/page-👟滑动窗口.b3cb4c10.js"><link rel="prefetch" href="/assets/js/page-👣IP协议基础.c423881a.js"><link rel="prefetch" href="/assets/js/page-👨‍💼TCP协议-简介.8dad7177.js"><link rel="prefetch" href="/assets/js/page-👨‍🔧IP-简介.45549536.js"><link rel="prefetch" href="/assets/js/page-👨‍🔧设计模式.2b288cfc.js"><link rel="prefetch" href="/assets/js/page-💁‍♂️Redis事务.2da37f16.js"><link rel="prefetch" href="/assets/js/page-💂面试知识点整理.53653cc8.js"><link rel="prefetch" href="/assets/js/page-💍HTTP协议的改进.9d91d303.js"><link rel="prefetch" href="/assets/js/page-💐Spring全家桶-简介.bc0ceb52.js"><link rel="prefetch" href="/assets/js/page-💼HTTP协议的请求方法.49ea5b30.js"><link rel="prefetch" href="/assets/js/page-🖐️存储引擎.51e90aae.js"><link rel="prefetch" href="/assets/js/page-🖖DDL.58e99d50.js"><link rel="prefetch" href="/assets/js/page-😀面向对象的特点.64db987a.js"><link rel="prefetch" href="/assets/js/page-😁Object类.bd3dee32.js"><link rel="prefetch" href="/assets/js/page-😆String类.6fe32326.js"><link rel="prefetch" href="/assets/js/page-😎泛型.9245d81a.js"><link rel="prefetch" href="/assets/js/page-😛关键字.1e781f13.js"><link rel="prefetch" href="/assets/js/page-😪反射.ef7a385f.js"><link rel="prefetch" href="/assets/js/page-😵异常.6c2ba11a.js"><link rel="prefetch" href="/assets/js/page-🙅‍♂️Redis淘汰策略.650f7bea.js"><link rel="prefetch" href="/assets/js/page-🙆‍♂️Redis持久化策略.d130b1b1.js"><link rel="prefetch" href="/assets/js/page-🙇‍♂️Redis基础.2c3c39e8.js"><link rel="prefetch" href="/assets/js/page-🙈JMM.3512b22b.js"><link rel="prefetch" href="/assets/js/page-🙉进程和线程.f7aa9975.js"><link rel="prefetch" href="/assets/js/page-🙊线程池.bab2c4d8.js"><link rel="prefetch" href="/assets/js/page-🙋‍♂️Redis底层实现.7416ea6f.js"><link rel="prefetch" href="/assets/js/page-🚥ZooKeeper.57458d21.js"><link rel="prefetch" href="/assets/js/page-🚵HashTable.ccce702b.js"><link rel="prefetch" href="/assets/js/page-🚶‍♂️超时重传机制.cfb21e2f.js"><link rel="prefetch" href="/assets/js/page-🤚范式.b6a8d503.js"><link rel="prefetch" href="/assets/js/page-🤝集群.bdd1180d.js"><link rel="prefetch" href="/assets/js/page-🤞锁.c12200cd.js"><link rel="prefetch" href="/assets/js/page-🤦‍♂️故障处理.80248294.js"><link rel="prefetch" href="/assets/js/page-🤪包装类和缓存池.4fa40654.js"><link rel="prefetch" href="/assets/js/page-🤴HTTP协议-简介.c55283d9.js"><link rel="prefetch" href="/assets/js/page-🤸ArrayList.f0cf8991.js"><link rel="prefetch" href="/assets/js/page-🤹LinkedList.caf8cd71.js"><link rel="prefetch" href="/assets/js/page-🤼HashMap.2ad7d223.js"><link rel="prefetch" href="/assets/js/page-🤾Vector.7740cb05.js"><link rel="prefetch" href="/assets/js/page-🥁好大夫在线.e46779d8.js"><link rel="prefetch" href="/assets/js/page-🦍无同步方案.9b8df198.js"><link rel="prefetch" href="/assets/js/page-🧏‍♂️Redis集群.6d3441ab.js"><link rel="prefetch" href="/assets/js/page-🧐其他.deb18f3f.js"><link rel="prefetch" href="/assets/js/page-🧘ConcurrentHashMap.a3e51c7d.js"><link rel="prefetch" href="/assets/js/page-🧙‍♂️内存管理.c1b418f2.js"><link rel="prefetch" href="/assets/js/page-🧚CPU缓存一致性.8647e92e.js"><link rel="prefetch" href="/assets/js/page-🧛‍♂️IO.3bf30d07.js"><link rel="prefetch" href="/assets/js/page-🧝‍♂️进程与线程.f1df829e.js"><link rel="prefetch" href="/assets/js/page-🧟锁.86b4ff29.js"><link rel="prefetch" href="/assets/js/page-🧣TCP协议基础.2e717ff6.js"><link rel="prefetch" href="/assets/js/page-🧤拥塞控制.9018c6ff.js"><link rel="prefetch" href="/assets/js/page-🧥HTTP协议基础.719b302d.js"><link rel="prefetch" href="/assets/js/page-🧩美团.7049187d.js"><link rel="prefetch" href="/assets/js/page-🧳建立与释放连接.b95bfaf5.js"><link rel="prefetch" href="/assets/js/page-🧶元保数科.aba682de.js"><link rel="prefetch" href="/assets/js/vendors~flowchart.846214db.js"><link rel="prefetch" href="/assets/js/vendors~mermaid.4a0cbbd3.js"><link rel="prefetch" href="/assets/js/vendors~photo-swipe.515ad438.js"><link rel="prefetch" href="/assets/js/vendors~reveal.b4fb0aa4.js"><link rel="prefetch" href="/assets/js/vendors~waline.c2d7e472.js">
    <link rel="stylesheet" href="/assets/css/0.styles.79654418.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container has-navbar has-sidebar has-anchor"><header class="navbar"><!----> <div class="content__navbar-start"></div> <button title="Sidebar Button" class="sidebar-button"><span class="icon"></span></button> <a href="/" class="home-link router-link-active"><img src="/icon.png" alt="Xiangyu's Blog" class="logo"> <!----> <span class="site-name can-hide">Xiangyu's Blog</span></a> <!----> <div class="content__navbar-center"></div> <div class="links"><button aria-hidden="true" class="color-button"><svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" class="skin-icon"><path d="M224 800c0 9.6 3.2 44.8 6.4 54.4 6.4 48-48 76.8-48 76.8s80 41.6 147.2 0 134.4-134.4
        38.4-195.2c-22.4-12.8-41.6-19.2-57.6-19.2C259.2 716.8 227.2 761.6 224 800zM560 675.2l-32
        51.2c-51.2 51.2-83.2 32-83.2 32 25.6 67.2 0 112-12.8 128 25.6 6.4 51.2 9.6 80 9.6 54.4 0
        102.4-9.6 150.4-32l0 0c3.2 0 3.2-3.2 3.2-3.2 22.4-16 12.8-35.2
        6.4-44.8-9.6-12.8-12.8-25.6-12.8-41.6 0-54.4 60.8-99.2 137.6-99.2 6.4 0 12.8 0 22.4
        0 12.8 0 38.4 9.6 48-25.6 0-3.2 0-3.2 3.2-6.4 0-3.2 3.2-6.4 3.2-6.4 6.4-16 6.4-16 6.4-19.2
        9.6-35.2 16-73.6 16-115.2 0-105.6-41.6-198.4-108.8-268.8C704 396.8 560 675.2 560 675.2zM224
        419.2c0-28.8 22.4-51.2 51.2-51.2 28.8 0 51.2 22.4 51.2 51.2 0 28.8-22.4 51.2-51.2 51.2C246.4
        470.4 224 448 224 419.2zM320 284.8c0-22.4 19.2-41.6 41.6-41.6 22.4 0 41.6 19.2 41.6 41.6 0
        22.4-19.2 41.6-41.6 41.6C339.2 326.4 320 307.2 320 284.8zM457.6 208c0-12.8 12.8-25.6 25.6-25.6
        12.8 0 25.6 12.8 25.6 25.6 0 12.8-12.8 25.6-25.6 25.6C470.4 233.6 457.6 220.8 457.6 208zM128
        505.6C128 592 153.6 672 201.6 736c28.8-60.8 112-60.8 124.8-60.8-16-51.2 16-99.2
        16-99.2l316.8-422.4c-48-19.2-99.2-32-150.4-32C297.6 118.4 128 291.2 128 505.6zM764.8
        86.4c-22.4 19.2-390.4 518.4-390.4 518.4-22.4 28.8-12.8 76.8 22.4 99.2l9.6 6.4c35.2 22.4
        80 12.8 99.2-25.6 0 0 6.4-12.8 9.6-19.2 54.4-105.6 275.2-524.8 288-553.6
        6.4-19.2-3.2-32-19.2-32C777.6 76.8 771.2 80 764.8 86.4z"></path></svg> <div class="color-picker-menu" style="display:none;"><div class="theme-options"><ul class="themecolor-select"><label for="themecolor-select">主题色:</label> <li><span class="default-theme"></span></li> </ul> <div class="darkmode-toggle"><label for="darkmode-toggle" class="desc">主题模式:</label> <div class="darkmode-switch"><div class="item day"><svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" class="icon light-icon"><path d="M512 256a42.667 42.667 0 0 0 42.667-42.667V128a42.667 42.667 0 0 0-85.334 0v85.333A42.667 42.667 0 0 0 512 256zm384 213.333h-85.333a42.667 42.667 0 0 0 0 85.334H896a42.667 42.667 0 0 0 0-85.334zM256 512a42.667 42.667 0 0 0-42.667-42.667H128a42.667 42.667 0 0 0 0 85.334h85.333A42.667 42.667 0 0 0 256 512zm9.387-298.667a42.667 42.667 0 0 0-59.307 62.72l61.44 59.307a42.667 42.667 0 0 0 31.147 11.947 42.667 42.667 0 0 0 30.72-13.227 42.667 42.667 0 0 0 0-60.16zm459.946 133.974a42.667 42.667 0 0 0 29.44-11.947l61.44-59.307a42.667 42.667 0 0 0-57.6-62.72l-61.44 60.587a42.667 42.667 0 0 0 0 60.16 42.667 42.667 0 0 0 28.16 13.227zM512 768a42.667 42.667 0 0 0-42.667 42.667V896a42.667 42.667 0 0 0 85.334 0v-85.333A42.667 42.667 0 0 0 512 768zm244.48-79.36a42.667 42.667 0 0 0-59.307 61.44l61.44 60.587a42.667 42.667 0 0 0 29.44 11.946 42.667 42.667 0 0 0 30.72-12.8 42.667 42.667 0 0 0 0-60.586zm-488.96 0-61.44 59.307a42.667 42.667 0 0 0 0 60.586 42.667 42.667 0 0 0 30.72 12.8 42.667 42.667 0 0 0 28.587-10.666l61.44-59.307a42.667 42.667 0 0 0-59.307-61.44zM512 341.333A170.667 170.667 0 1 0 682.667 512 170.667 170.667 0 0 0 512 341.333z" fill="currentColor"></path></svg></div> <div class="item auto active"><svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" class="icon auto-icon"><path d="M460.864 539.072H564.8L510.592 376l-49.728 163.072zM872 362.368V149.504H659.648L510.528 0l-149.12 149.504H149.12v212.928L0 511.872l149.12 149.504v212.928h212.352l149.12 149.504 149.12-149.504h212.352V661.376l149.12-149.504L872 362.368zM614.464 693.12l-31.616-90.624H438.272l-31.616 90.624h-85.888l144.576-407.68h90.368l144.576 407.68h-85.824zm0 0" fill="currentColor"></path></svg></div> <div class="item night"><svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" class="icon dark-icon"><path d="M935.539 630.402c-11.43-11.432-28.674-14.739-43.531-8.354-46.734 20.103-96.363 30.297-147.508 30.297-99.59 0-193.221-38.784-263.64-109.203-108.637-108.637-139.61-270.022-78.908-411.148a39.497 39.497 0 0 0-51.886-51.887c-52.637 22.64-100.017 54.81-140.826 95.616-85.346 85.346-132.346 198.821-132.346 319.52 0 120.7 47.001 234.172 132.347 319.519S408.063 947.11 528.76 947.11c120.7 0 234.172-47.003 319.52-132.351 40.809-40.81 72.978-88.19 95.616-140.826a39.497 39.497 0 0 0-8.356-43.532z" fill="currentColor"></path></svg></div></div> <!----></div></div></div></button> <div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/" class="nav-link router-link-active"><i class="iconfont icon-home"></i>
  主页
</a></div><div class="nav-item"><a href="/interview/" class="nav-link router-link-active active"><i class="iconfont icon-launch"></i>
  面试题整理
</a></div></nav> <!----> <a rel="noopener noreferrer" href="https://github.com/lxy1152/lxy1152.github.io" target="_blank" class="repo-link can-hide">
  GitHub
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> <!----> <div class="content__navbar-end"></div></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><!----> <!----> <div class="content__sidebar-top"></div> <nav class="sidebar-nav-links"><div class="nav-item"><a href="/" class="nav-link router-link-active"><i class="iconfont icon-home"></i>
  主页
</a></div><div class="nav-item"><a href="/interview/" class="nav-link router-link-active active"><i class="iconfont icon-launch"></i>
  面试题整理
</a></div> <a rel="noopener noreferrer" href="https://github.com/lxy1152/lxy1152.github.io" target="_blank" class="repo-link">
  GitHub
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav> <!----> <div class="content__sidebar-center"></div> <ul class="sidebar-links"><li><a href="/interview/" aria-current="page" class="sidebar-link">💂 面试知识点整理</a></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading clickable"><!----> <span class="title">😉 Java 基础</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading clickable"><!----> <span class="title">🌈 Java 容器</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading clickable"><!----> <span class="title">🐺 Java 并发</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading clickable"><!----> <span class="title">⛳ Java I/O</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading clickable"><!----> <span class="title">🌏 JVM</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading clickable open"><!----> <span class="title">🌱 框架使用</span> <span class="arrow down"></span></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/interview/framework/" aria-current="page" class="sidebar-link">🌀 框架使用 - 简介</a></li><li><section class="sidebar-group collapsable is-sub-group depth-1"><p class="sidebar-heading clickable open"><!----> <span class="title">🌸 Spring 全家桶</span> <span class="arrow down"></span></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/interview/framework/spring/" aria-current="page" class="sidebar-link">💐 Spring 全家桶 - 简介</a></li><li><a href="/interview/framework/spring/spring/" aria-current="page" class="active sidebar-link">🌲 Spring</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/interview/framework/spring/spring/#什么是-spring-框架" class="sidebar-link">什么是 Spring 框架？</a></li><li class="sidebar-sub-header"><a href="/interview/framework/spring/spring/#spring-有哪些模块" class="sidebar-link">Spring 有哪些模块？</a></li><li class="sidebar-sub-header"><a href="/interview/framework/spring/spring/#什么是-ioc" class="sidebar-link">什么是 IoC？</a></li><li class="sidebar-sub-header"><a href="/interview/framework/spring/spring/#什么是-aop" class="sidebar-link">什么是 AOP？</a></li><li class="sidebar-sub-header"><a href="/interview/framework/spring/spring/#spring-框架中使用的设计模式" class="sidebar-link">Spring 框架中使用的设计模式？</a></li><li class="sidebar-sub-header"><a href="/interview/framework/spring/spring/#spring-bean" class="sidebar-link">Spring Bean</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/interview/framework/spring/spring/#component-和-bean-注解的区别" class="sidebar-link heading3">@Component 和 @Bean 注解的区别？</a></li><li class="sidebar-sub-header"><a href="/interview/framework/spring/spring/#bean-的生命周期" class="sidebar-link heading3">Bean 的生命周期？</a></li><li class="sidebar-sub-header"><a href="/interview/framework/spring/spring/#bean-的作用域有哪些" class="sidebar-link heading3">Bean 的作用域有哪些？</a></li><li class="sidebar-sub-header"><a href="/interview/framework/spring/spring/#常见的-bean-转换工具有哪些" class="sidebar-link heading3">常见的 Bean 转换工具有哪些？</a></li><li class="sidebar-sub-header"><a href="/interview/framework/spring/spring/#beanfactory-和-factorybean-有哪些区别" class="sidebar-link heading3">BeanFactory 和 FactoryBean 有哪些区别？</a></li><li class="sidebar-sub-header"><a href="/interview/framework/spring/spring/#spring-的三级缓存" class="sidebar-link heading3">Spring 的三级缓存？</a></li></ul></li><li class="sidebar-sub-header"><a href="/interview/framework/spring/spring/#spring-事务" class="sidebar-link">Spring 事务</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/interview/framework/spring/spring/#管理事务的两种方式" class="sidebar-link heading3">管理事务的两种方式？</a></li><li class="sidebar-sub-header"><a href="/interview/framework/spring/spring/#事务隔离级别有哪些" class="sidebar-link heading3">事务隔离级别有哪些？</a></li><li class="sidebar-sub-header"><a href="/interview/framework/spring/spring/#事务的传播方式有哪几种" class="sidebar-link heading3">事务的传播方式有哪几种？</a></li><li class="sidebar-sub-header"><a href="/interview/framework/spring/spring/#哪些方法可以开启事务" class="sidebar-link heading3">哪些方法可以开启事务？</a></li><li class="sidebar-sub-header"><a href="/interview/framework/spring/spring/#什么情况下会导致事务回滚" class="sidebar-link heading3">什么情况下会导致事务回滚？</a></li><li class="sidebar-sub-header"><a href="/interview/framework/spring/spring/#在什么场景下会导致事务失效" class="sidebar-link heading3">在什么场景下会导致事务失效？</a></li></ul></li></ul></li><li><a href="/interview/framework/spring/spring-mvc/" class="sidebar-link">🌳 SpringMVC</a></li><li><a href="/interview/framework/spring/springboot/" class="sidebar-link">🌴 SpringBoot</a></li><li><a href="/interview/framework/spring/springcloud/" class="sidebar-link">🌵 SpringCloud</a></li></ul></section></li><li><section class="sidebar-group collapsable is-sub-group depth-1"><p class="sidebar-heading clickable"><!----> <span class="title">💮 MyBatis</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable is-sub-group depth-1"><p class="sidebar-heading clickable"><!----> <span class="title">🏵️ 通讯</span> <span class="arrow right"></span></p> <!----></section></li></ul></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading clickable"><!----> <span class="title">👊 MySQL</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading clickable"><!----> <span class="title">🤷‍♂️ Redis</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading clickable"><!----> <span class="title">🎠 中间件</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading clickable"><!----> <span class="title">👨‍👧‍👧 计算机网络</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading clickable"><!----> <span class="title">🦸 操作系统</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading clickable"><!----> <span class="title">🏭 设计思想</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading clickable"><!----> <span class="title">📚 面经</span> <span class="arrow right"></span></p> <!----></section></li></ul> <!----> <div class="content__sidebar-bottom"></div> <!----></aside> <main class="page"><nav class="breadcrumb"><ol vocab="https://schema.org/" typeof="BreadcrumbList"><li property="itemListElement" typeof="ListItem"><a href="/interview/" property="item" typeof="WebPage" class="router-link-active"><!----> <span property="name">💂 面试知识点整理</span></a> <meta property="position" content="1"></li><li property="itemListElement" typeof="ListItem"><a href="/interview/framework/" property="item" typeof="WebPage" class="router-link-active"><!----> <span property="name">🌀 框架使用 - 简介</span></a> <meta property="position" content="2"></li><li property="itemListElement" typeof="ListItem"><a href="/interview/framework/spring/" property="item" typeof="WebPage" class="router-link-active"><!----> <span property="name">💐 Spring 全家桶 - 简介</span></a> <meta property="position" content="3"></li><li property="itemListElement" typeof="ListItem" class="is-active"><a href="/interview/framework/spring/spring/" aria-current="page" property="item" typeof="WebPage" class="router-link-exact-active router-link-active"><!----> <span property="name">🌲 Spring</span></a> <meta property="position" content="4"></li></ol></nav> <!----> <div class="content__page-top"></div> <div vocab="https://schema.org/" typeof="Article" class="page-title"><h1><!----> <span property="headline">🌲 Spring</span></h1> <div class="page-info"><!----> <span aria-label="作者🖊" data-balloon-pos="down"><svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" class="icon author-icon"><path d="M649.6 633.6c86.4-48 147.2-144 147.2-249.6 0-160-128-288-288-288s-288 128-288 288c0 108.8 57.6 201.6 147.2 249.6-121.6 48-214.4 153.6-240 288-3.2 9.6 0 19.2 6.4 25.6 3.2 9.6 12.8 12.8 22.4 12.8h704c9.6 0 19.2-3.2 25.6-12.8 6.4-6.4 9.6-16 6.4-25.6-25.6-134.4-121.6-240-243.2-288z" fill="currentColor"></path></svg> <span property="author">Xiangyu Li</span></span><span aria-label="访问量🔢" data-balloon-pos="down" class="visitor-info"><svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" class="icon eye-icon"><path d="M992 512.096c0-5.76-.992-10.592-1.28-11.136-.192-2.88-1.152-8.064-2.08-10.816-.256-.672-.544-1.376-.832-2.08-.48-1.568-1.024-3.104-1.6-4.32C897.664 290.112 707.104 160 512 160c-195.072 0-385.632 130.016-473.76 322.592-1.056 2.112-1.792 4.096-2.272 5.856a55.512 55.512 0 0 0-.64 1.6c-1.76 5.088-1.792 8.64-1.632 7.744-.832 3.744-1.568 11.168-1.568 11.168-.224 2.272-.224 4.032.032 6.304 0 0 .736 6.464 1.088 7.808.128 1.824.576 4.512 1.12 6.976h-.032c.448 2.08 1.12 4.096 1.984 6.08.48 1.536.992 2.976 1.472 4.032C126.432 733.856 316.992 864 512 864c195.136 0 385.696-130.048 473.216-321.696 1.376-2.496 2.24-4.832 2.848-6.912.256-.608.48-1.184.672-1.728 1.536-4.48 1.856-8.32 1.728-8.32l-.032.032c.608-3.104 1.568-7.744 1.568-13.28zM512 672c-88.224 0-160-71.776-160-160s71.776-160 160-160 160 71.776 160 160-71.776 160-160 160z" fill="currentColor"></path></svg> <span id="/interview/framework/spring/spring/" data-flag-title="🌲 Spring" class="leancloud_visitors"><span class="leancloud-visitors-count">...</span></span></span><span aria-label="写作日期📅" data-balloon-pos="down" class="time-info"><svg viewBox="0 0 1030 1024" xmlns="http://www.w3.org/2000/svg" class="icon calendar-icon"><path d="M716.4 110.137c0-18.753-14.72-33.473-33.472-33.473-18.753 0-33.473 14.72-33.473 33.473v33.473h66.993v-33.473zm-334.87 0c0-18.753-14.72-33.473-33.473-33.473s-33.52 14.72-33.52 33.473v33.473h66.993v-33.473zm468.81 33.52H716.4v100.465c0 18.753-14.72 33.473-33.472 33.473a33.145 33.145 0 0 1-33.473-33.473V143.657H381.53v100.465c0 18.753-14.72 33.473-33.473 33.473a33.145 33.145 0 0 1-33.473-33.473V143.657H180.6A134.314 134.314 0 0 0 46.66 277.595v535.756A134.314 134.314 0 0 0 180.6 947.289h669.74a134.36 134.36 0 0 0 133.94-133.938V277.595a134.314 134.314 0 0 0-133.94-133.938zm33.473 267.877H147.126a33.145 33.145 0 0 1-33.473-33.473c0-18.752 14.72-33.473 33.473-33.473h736.687c18.752 0 33.472 14.72 33.472 33.473a33.145 33.145 0 0 1-33.472 33.473z" fill="currentColor"></path></svg> <span property="datePublished">2021-8-1</span></span><!----><!----><span aria-label="阅读时间⌛" data-balloon-pos="down" class="reading-time-info"><svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" class="icon timer-icon"><path d="M799.387 122.15c4.402-2.978 7.38-7.897 7.38-13.463v-1.165c0-8.933-7.38-16.312-16.312-16.312H256.33c-8.933 0-16.311 7.38-16.311 16.312v1.165c0 5.825 2.977 10.874 7.637 13.592 4.143 194.44 97.22 354.963 220.201 392.763-122.204 37.542-214.893 196.511-220.2 389.397-4.661 5.049-7.638 11.651-7.638 19.03v5.825h566.49v-5.825c0-7.379-2.849-13.981-7.509-18.9-5.049-193.016-97.867-351.985-220.2-389.527 123.24-37.67 216.446-198.453 220.588-392.892zM531.16 450.445v352.632c117.674 1.553 211.787 40.778 211.787 88.676H304.097c0-48.286 95.149-87.382 213.728-88.676V450.445c-93.077-3.107-167.901-81.297-167.901-177.093 0-8.803 6.99-15.793 15.793-15.793 8.803 0 15.794 6.99 15.794 15.793 0 80.261 63.69 145.635 142.01 145.635s142.011-65.374 142.011-145.635c0-8.803 6.99-15.793 15.794-15.793s15.793 6.99 15.793 15.793c0 95.019-73.789 172.82-165.96 177.093z" fill="currentColor"></path></svg> <span>大约 12 分钟</span> <meta property="timeRequired" content="PT12M"></span></div> <!----> <hr></div> <div class="anchor-place-holder"><aside id="anchor"><div class="anchor-wrapper"><ul class="anchor-list"><li class="anchor"><a href="/interview/framework/spring/spring/#什么是-spring-框架" class="anchor-link heading2"><div>什么是 Spring 框架？</div></a></li><li class="anchor"><a href="/interview/framework/spring/spring/#spring-有哪些模块" class="anchor-link heading2"><div>Spring 有哪些模块？</div></a></li><li class="anchor"><a href="/interview/framework/spring/spring/#什么是-ioc" class="anchor-link heading2"><div>什么是 IoC？</div></a></li><li class="anchor"><a href="/interview/framework/spring/spring/#什么是-aop" class="anchor-link heading2"><div>什么是 AOP？</div></a></li><li class="anchor"><a href="/interview/framework/spring/spring/#spring-框架中使用的设计模式" class="anchor-link heading2"><div>Spring 框架中使用的设计模式？</div></a></li><li class="anchor"><a href="/interview/framework/spring/spring/#spring-bean" class="anchor-link heading2"><div>Spring Bean</div></a></li><li class="anchor"><a href="/interview/framework/spring/spring/#component-和-bean-注解的区别" class="anchor-link heading3"><div>@Component 和 @Bean 注解的区别？</div></a></li><li class="anchor"><a href="/interview/framework/spring/spring/#bean-的生命周期" class="anchor-link heading3"><div>Bean 的生命周期？</div></a></li><li class="anchor"><a href="/interview/framework/spring/spring/#bean-的作用域有哪些" class="anchor-link heading3"><div>Bean 的作用域有哪些？</div></a></li><li class="anchor"><a href="/interview/framework/spring/spring/#常见的-bean-转换工具有哪些" class="anchor-link heading3"><div>常见的 Bean 转换工具有哪些？</div></a></li><li class="anchor"><a href="/interview/framework/spring/spring/#beanfactory-和-factorybean-有哪些区别" class="anchor-link heading3"><div>BeanFactory 和 FactoryBean 有哪些区别？</div></a></li><li class="anchor"><a href="/interview/framework/spring/spring/#spring-的三级缓存" class="anchor-link heading3"><div>Spring 的三级缓存？</div></a></li><li class="anchor"><a href="/interview/framework/spring/spring/#spring-事务" class="anchor-link heading2"><div>Spring 事务</div></a></li><li class="anchor"><a href="/interview/framework/spring/spring/#管理事务的两种方式" class="anchor-link heading3"><div>管理事务的两种方式？</div></a></li><li class="anchor"><a href="/interview/framework/spring/spring/#事务隔离级别有哪些" class="anchor-link heading3"><div>事务隔离级别有哪些？</div></a></li><li class="anchor"><a href="/interview/framework/spring/spring/#事务的传播方式有哪几种" class="anchor-link heading3"><div>事务的传播方式有哪几种？</div></a></li><li class="anchor"><a href="/interview/framework/spring/spring/#哪些方法可以开启事务" class="anchor-link heading3"><div>哪些方法可以开启事务？</div></a></li><li class="anchor"><a href="/interview/framework/spring/spring/#什么情况下会导致事务回滚" class="anchor-link heading3"><div>什么情况下会导致事务回滚？</div></a></li><li class="anchor"><a href="/interview/framework/spring/spring/#在什么场景下会导致事务失效" class="anchor-link heading3"><div>在什么场景下会导致事务失效？</div></a></li></ul></div></aside></div> <!----> <div class="content__content-top"></div> <div class="theme-default-content content__default"><h2 id="什么是-spring-框架"><a href="#什么是-spring-框架" class="header-anchor">#</a> 什么是 Spring 框架？</h2> <p>Spring 是一个轻量级开发框架，旨在提高开发人员的开发效率以及系统的可维护性。一般说的 Spring 框架指的都是 Spring Framework，它是很多模块的集合，使用这些模块可以很方便地协助开发人员进行开发。</p> <p>Spring 框架的特点：</p> <ul><li>轻量：Spring 是轻量的</li> <li>控制反转：Spring 通过控制反转实现了解耦</li> <li>面向切面的编程（AOP）：Spring 支持面向切面的编程，并且把应用业务逻辑和系统服务分开</li> <li>容器：Spring 包含并管理应用中对象的生命周期和配置</li> <li>MVC 框架：Spring 的 WEB 框架是个精心设计的框架，是 Web 框架的一个很好的替代品</li> <li>事务管理：Spring 提供了一个持续的事务管理接口</li> <li>异常处理：Spring 提供方便的 API 把具体技术相关的异常（比如由JDBC，Hibernate or JDO抛出的）转化为一致的 unchecked 异常。</li></ul> <h2 id="spring-有哪些模块"><a href="#spring-有哪些模块" class="header-anchor">#</a> Spring 有哪些模块？</h2> <div class="custom-block center"><p><img src="https://i.loli.net/2021/07/31/7UEfnFxiscSywvQ.png" alt="Spring模块.png"></p></div> <h2 id="什么是-ioc"><a href="#什么是-ioc" class="header-anchor">#</a> 什么是 IoC？<span class="badge error" style="vertical-align:top;" data-v-7b453e57>重点</span></h2> <p>IoC（Inverse of Control，控制反转）是一种设计思想，就是将原本在程序中手动创建对象的控制权，交由 Spring 来管理。IoC 在其他语言中也有应用，并非 Spring 特有。IoC 容器是 Spring 用来实现 IoC 的载体，IoC 容器实际上就是个 <code>Map</code>，其中存放的是各种对象。IoC 容器就像是一个工厂一样，当需要创建一个对象的时候，只需要配置好配置文件或者注解，完全不用考虑对象是如何被创建出来的。Spring 早期版本一般是通过 XML 文件来配置 Bean，目前更为流行的是通过注解来进行配置。</p> <h2 id="什么是-aop"><a href="#什么是-aop" class="header-anchor">#</a> 什么是 AOP？<span class="badge error" style="vertical-align:top;" data-v-7b453e57>重点</span></h2> <p>AOP（Aspect-Oriented Programming，面向切面编程）能够将那些与业务无关，却为业务模块所共同调用的逻辑或责任（例如事务处理、日志管理、权限控制等）封装起来，便于减少系统的重复代码，降低模块间的耦合度，并有利于未来的可拓展性和可维护性。Spring AOP 是基于动态代理实现的，如果要代理的对象实现了某个接口，那么 Spring AOP 会使用 JDKProxy 去创建代理对象，而对于没有实现接口的对象，会使用 CGLib 做代理，如下图所示：</p> <div class="custom-block center"><p><img src="https://i.loli.net/2021/07/31/fnhaAE5dxJw3pq6.png" alt="动态代理.png"></p></div> <h2 id="spring-框架中使用的设计模式"><a href="#spring-框架中使用的设计模式" class="header-anchor">#</a> Spring 框架中使用的设计模式？<span class="badge error" style="vertical-align:top;" data-v-7b453e57>重点</span></h2> <ul><li>工厂设计模式：Spring 使用工厂模式，通过 <code>BeanFactory</code>、<code>ApplicationContext</code> 创建 Bean</li> <li>代理设计模式：Spring AOP 功能的实现</li> <li>单例设计模式：Spring 中的 Bean 默认都是单例的</li> <li>包装器设计模式：项目需要连接多个数据库，而且不同的客户在每次访问中根据需要会去访问不同的数据库，这种模式可以根据客户的需求能够动态切换不同的数据源</li> <li>观察者模式: Spring 事件驱动模型</li> <li>适配器模式：Spring AOP 的增强或通知（Advice）使用到了适配器模式，Spring MVC 中也使用到了适配器模式适配 Controller</li></ul> <h2 id="spring-bean"><a href="#spring-bean" class="header-anchor">#</a> Spring Bean</h2> <h3 id="component-和-bean-注解的区别"><a href="#component-和-bean-注解的区别" class="header-anchor">#</a> @Component 和 @Bean 注解的区别？<span class="badge error" style="vertical-align:top;" data-v-7b453e57>重点</span></h3> <h4 id="作用对象不同"><a href="#作用对象不同" class="header-anchor">#</a> <strong>作用对象不同</strong></h4> <p><code>@Component</code> 注解作用于类，而 <code>@Bean</code> 注解作用于方法。</p> <h4 id="含义不同"><a href="#含义不同" class="header-anchor">#</a> <strong>含义不同</strong></h4> <p>因为 <code>@Component</code> 注解是作用于类的，所以它通常是通过类路径扫描来自动侦测以及自动装配到 Spring 容器中的（通过 <code>@ComponentScan</code> 注解定义要扫描的路径）。<code>@Bean</code> 注解作用于方法，它注明了某个方法会产生一个 Bean。</p> <h4 id="bean-注解能力更强"><a href="#bean-注解能力更强" class="header-anchor">#</a> <strong>@Bean 注解能力更强</strong></h4> <p>如果需要引用第三方库中的类到 Spring 容器中，那么就只能通过 <code>@Bean</code> 注解来实现。</p> <p>下面为两种注解的代码示例：</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">// Bean 注解代码示例</span>
<span class="token annotation punctuation">@Configuration</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">MyConfiguration</span> <span class="token punctuation">{</span>
    <span class="token annotation punctuation">@Bean</span>
    <span class="token keyword">public</span> <span class="token class-name">MyBean</span> <span class="token function">createMyBean</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">MyBean</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token comment">// Component 注解代码示例</span>
<span class="token annotation punctuation">@Component</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">MyComponent</span> <span class="token punctuation">{</span>
    <span class="token comment">// fields and functions</span>
<span class="token punctuation">}</span>

<span class="token annotation punctuation">@Service</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">MyService</span> <span class="token punctuation">{</span>
    <span class="token annotation punctuation">@Autowried</span>
    <span class="token class-name">MyComponent</span> myComponent<span class="token punctuation">;</span>
    
    <span class="token comment">// fields and functions</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br></div></div><div class="custom-block tip"><p class="custom-block-title">Bean 的装配</p> <p>一般使用 <code>@Autowired</code> 注解自动装配 Bean，要想把类标识成可用于 <code>@Autowired</code> 注解自动装配的 Bean，除了上面提到的这两种注解以外，还可以使用以下的三个注解。这些注解没有功能上的扩展，只是为了语义清晰：</p> <ul><li><code>@Repository</code>: 对应持久层，即 Dao 层，主要用于数据库相关操作</li> <li><code>@Service</code>: 对应服务层，主要涉及一些复杂的业务逻辑，需要用到 Dao 层</li> <li><code>@Controller</code>: 对应 Spring MVC 控制层，主要用于接受用户请求并调用 Service 层返回数据给前端页面</li></ul></div> <h3 id="bean-的生命周期"><a href="#bean-的生命周期" class="header-anchor">#</a> Bean 的生命周期？<span class="badge error" style="vertical-align:top;" data-v-7b453e57>重点</span></h3> <div class="custom-block center"><p><img src="https://i.loli.net/2021/07/31/VtnmjZBhIK6scJM.png" alt="Bean生命周期.jpg"></p></div> <div class="custom-block tip"><p class="custom-block-title">@PostConstruct 和 @PreDestroy</p> <p><code>@PostConstruct</code> 和 <code>@PreDestroy</code> 注解不是 Spring 提供的注解，而是 javax 包中提供的注解，Spring 支持使用这两个注解。</p></div> <p>示例代码如下：</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">// 以下内容为Bean的实现</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>beans<span class="token punctuation">.</span></span><span class="token class-name">BeansException</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>beans<span class="token punctuation">.</span>factory<span class="token punctuation">.</span></span><span class="token operator">*</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span></span><span class="token class-name">ApplicationContext</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span></span><span class="token class-name">ApplicationContextAware</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span></span><span class="token class-name">EnvironmentAware</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span></span><span class="token class-name">ResourceLoaderAware</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>core<span class="token punctuation">.</span>env<span class="token punctuation">.</span></span><span class="token class-name">Environment</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>core<span class="token punctuation">.</span>env<span class="token punctuation">.</span></span><span class="token class-name">PropertySource</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>core<span class="token punctuation">.</span>io<span class="token punctuation">.</span></span><span class="token class-name">ResourceLoader</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>stereotype<span class="token punctuation">.</span></span><span class="token class-name">Component</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>context<span class="token punctuation">.</span>support<span class="token punctuation">.</span></span><span class="token class-name">StandardServletEnvironment</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">PostConstruct</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">PreDestroy</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Map</span><span class="token punctuation">;</span>

<span class="token comment">/**
 * 以下函数的调用顺序与函数编写顺序相同
 *
 * @author lixiangyu
 */</span>
<span class="token annotation punctuation">@Component</span><span class="token punctuation">(</span><span class="token string">&quot;MyBean&quot;</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">MyBean</span> <span class="token keyword">implements</span> <span class="token class-name">InitializingBean</span><span class="token punctuation">,</span> <span class="token class-name">DisposableBean</span><span class="token punctuation">,</span> <span class="token class-name">ApplicationContextAware</span><span class="token punctuation">,</span> <span class="token class-name">BeanFactoryAware</span><span class="token punctuation">,</span>
        <span class="token class-name">BeanClassLoaderAware</span><span class="token punctuation">,</span> <span class="token class-name">BeanNameAware</span><span class="token punctuation">,</span> <span class="token class-name">EnvironmentAware</span><span class="token punctuation">,</span> <span class="token class-name">ResourceLoaderAware</span> <span class="token punctuation">{</span>
    <span class="token comment">/**
     * 获取Bean名称
     *
     * @param s 名称
     */</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setBeanName</span><span class="token punctuation">(</span><span class="token class-name">String</span> s<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;bean name is: &quot;</span> <span class="token operator">+</span> s<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 获取类加载器
     *
     * @param classLoader 类加载器
     */</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setBeanClassLoader</span><span class="token punctuation">(</span><span class="token class-name">ClassLoader</span> classLoader<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;class loader: &quot;</span> <span class="token operator">+</span> classLoader<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 获取Bean Factory
     */</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setBeanFactory</span><span class="token punctuation">(</span><span class="token class-name">BeanFactory</span> beanFactory<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeansException</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;set bean factory... &quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 获取运行时环境变量
     */</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setEnvironment</span><span class="token punctuation">(</span><span class="token class-name">Environment</span> environment<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 这里是在获取nacos中的配置项并转为Map</span>
        <span class="token class-name">PropertySource</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> propertySource
                <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">StandardServletEnvironment</span><span class="token punctuation">)</span> environment<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getPropertySources</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">&quot;demo.yaml|DEFAULT_GROUP|||192.168.4.185:8848|||||||&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> obj <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">)</span> propertySource<span class="token punctuation">.</span><span class="token function">getSource</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;set environment...&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 获取资源加载器
     */</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setResourceLoader</span><span class="token punctuation">(</span><span class="token class-name">ResourceLoader</span> resourceLoader<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;set resource loader...&quot;</span> <span class="token operator">+</span> resourceLoader<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 获取上下文
     *
     * @param applicationContext 上下文
     * @throws BeansException beansException
     */</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setApplicationContext</span><span class="token punctuation">(</span><span class="token class-name">ApplicationContext</span> applicationContext<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeansException</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;set application context...&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// ------ Bean Post Processor begin -----------</span>
    <span class="token comment">// 在这里会调用postProcessBeforeInitialization方法</span>

    <span class="token comment">/**
     * 在类实例化并且设置完属性后调用
     */</span>
    <span class="token annotation punctuation">@PostConstruct</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">postConstruct</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;postConstruct...&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 初始化方法
     *
     * @throws Exception 异常
     */</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">afterPropertiesSet</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;after properties set...&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// 在这里会调用postProcessAfterInitialization方法</span>
    <span class="token comment">// ------ Bean Post Processor end ------------</span>

    <span class="token comment">/**
     * Bean销毁时执行的方法
     */</span>
    <span class="token annotation punctuation">@PreDestroy</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">preDestroy</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;pre destroy...&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * Bean销毁时执行的方法
     *
     * @throws Exception 异常
     */</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">destroy</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;destroy...&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token comment">// 以下内容为后置处理器BeanPostProcessor的实现</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>beans<span class="token punctuation">.</span></span><span class="token class-name">BeansException</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>beans<span class="token punctuation">.</span>factory<span class="token punctuation">.</span>config<span class="token punctuation">.</span></span><span class="token class-name">BeanPostProcessor</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>stereotype<span class="token punctuation">.</span></span><span class="token class-name">Component</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Component</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">MyBeanPostProcessor</span> <span class="token keyword">implements</span> <span class="token class-name">BeanPostProcessor</span> <span class="token punctuation">{</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">postProcessBeforeInitialization</span><span class="token punctuation">(</span><span class="token class-name">Object</span> bean<span class="token punctuation">,</span> <span class="token class-name">String</span> beanName<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeansException</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>bean <span class="token keyword">instanceof</span> <span class="token class-name">MyBean</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;bean post process before init...  &quot;</span> <span class="token operator">+</span> bean <span class="token operator">+</span> <span class="token string">&quot; &quot;</span> <span class="token operator">+</span> beanName<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">return</span> <span class="token class-name">BeanPostProcessor</span><span class="token punctuation">.</span><span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">postProcessBeforeInitialization</span><span class="token punctuation">(</span>bean<span class="token punctuation">,</span> beanName<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">postProcessAfterInitialization</span><span class="token punctuation">(</span><span class="token class-name">Object</span> bean<span class="token punctuation">,</span> <span class="token class-name">String</span> beanName<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeansException</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>bean <span class="token keyword">instanceof</span> <span class="token class-name">MyBean</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;bean post process after init...  &quot;</span> <span class="token operator">+</span> bean <span class="token operator">+</span> <span class="token string">&quot; &quot;</span> <span class="token operator">+</span> beanName<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">return</span> <span class="token class-name">BeanPostProcessor</span><span class="token punctuation">.</span><span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">postProcessAfterInitialization</span><span class="token punctuation">(</span>bean<span class="token punctuation">,</span> beanName<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br><span class="line-number">47</span><br><span class="line-number">48</span><br><span class="line-number">49</span><br><span class="line-number">50</span><br><span class="line-number">51</span><br><span class="line-number">52</span><br><span class="line-number">53</span><br><span class="line-number">54</span><br><span class="line-number">55</span><br><span class="line-number">56</span><br><span class="line-number">57</span><br><span class="line-number">58</span><br><span class="line-number">59</span><br><span class="line-number">60</span><br><span class="line-number">61</span><br><span class="line-number">62</span><br><span class="line-number">63</span><br><span class="line-number">64</span><br><span class="line-number">65</span><br><span class="line-number">66</span><br><span class="line-number">67</span><br><span class="line-number">68</span><br><span class="line-number">69</span><br><span class="line-number">70</span><br><span class="line-number">71</span><br><span class="line-number">72</span><br><span class="line-number">73</span><br><span class="line-number">74</span><br><span class="line-number">75</span><br><span class="line-number">76</span><br><span class="line-number">77</span><br><span class="line-number">78</span><br><span class="line-number">79</span><br><span class="line-number">80</span><br><span class="line-number">81</span><br><span class="line-number">82</span><br><span class="line-number">83</span><br><span class="line-number">84</span><br><span class="line-number">85</span><br><span class="line-number">86</span><br><span class="line-number">87</span><br><span class="line-number">88</span><br><span class="line-number">89</span><br><span class="line-number">90</span><br><span class="line-number">91</span><br><span class="line-number">92</span><br><span class="line-number">93</span><br><span class="line-number">94</span><br><span class="line-number">95</span><br><span class="line-number">96</span><br><span class="line-number">97</span><br><span class="line-number">98</span><br><span class="line-number">99</span><br><span class="line-number">100</span><br><span class="line-number">101</span><br><span class="line-number">102</span><br><span class="line-number">103</span><br><span class="line-number">104</span><br><span class="line-number">105</span><br><span class="line-number">106</span><br><span class="line-number">107</span><br><span class="line-number">108</span><br><span class="line-number">109</span><br><span class="line-number">110</span><br><span class="line-number">111</span><br><span class="line-number">112</span><br><span class="line-number">113</span><br><span class="line-number">114</span><br><span class="line-number">115</span><br><span class="line-number">116</span><br><span class="line-number">117</span><br><span class="line-number">118</span><br><span class="line-number">119</span><br><span class="line-number">120</span><br><span class="line-number">121</span><br><span class="line-number">122</span><br><span class="line-number">123</span><br><span class="line-number">124</span><br><span class="line-number">125</span><br><span class="line-number">126</span><br><span class="line-number">127</span><br><span class="line-number">128</span><br><span class="line-number">129</span><br><span class="line-number">130</span><br><span class="line-number">131</span><br><span class="line-number">132</span><br><span class="line-number">133</span><br><span class="line-number">134</span><br><span class="line-number">135</span><br><span class="line-number">136</span><br><span class="line-number">137</span><br><span class="line-number">138</span><br><span class="line-number">139</span><br><span class="line-number">140</span><br><span class="line-number">141</span><br><span class="line-number">142</span><br><span class="line-number">143</span><br><span class="line-number">144</span><br><span class="line-number">145</span><br><span class="line-number">146</span><br><span class="line-number">147</span><br><span class="line-number">148</span><br><span class="line-number">149</span><br><span class="line-number">150</span><br><span class="line-number">151</span><br><span class="line-number">152</span><br></div></div><h3 id="bean-的作用域有哪些"><a href="#bean-的作用域有哪些" class="header-anchor">#</a> Bean 的作用域有哪些？<span class="badge error" style="vertical-align:top;" data-v-7b453e57>重点</span></h3> <table><thead><tr><th style="text-align:center;">名称</th> <th style="text-align:center;">含义</th></tr></thead> <tbody><tr><td style="text-align:center;">Singleton</td> <td style="text-align:center;">单例，Spring 中的 Bean 默认都是单例的。</td></tr> <tr><td style="text-align:center;">Prototype</td> <td style="text-align:center;">每次请求都会创建一个新的 Bean 实例。</td></tr> <tr><td style="text-align:center;">Request</td> <td style="text-align:center;">每个 HTTP 请求都会产生一个新的 Bean，这个 Bean 仅在当前 HTTP request 内有效。</td></tr> <tr><td style="text-align:center;">Session</td> <td style="text-align:center;">每个 HTTP 请求都会产生一个新的 Bean，这个 Bean 仅在当前 HTTP session 内有效。</td></tr> <tr><td style="text-align:center;">Global-Session</td> <td style="text-align:center;">全局 session 作用域，仅仅在基于 Portlet 的 web 应用中才有意义，Spring5 已经没有了。Portlet 是能够生成语义代码（例如：HTML）片段的小型 Java Web 插件，它们基于 Portlet 容器，可以像 servlet 一样处理 HTTP 请求，但是与 servlet 不同的是每个 portlet 都有不同的会话。</td></tr></tbody></table> <h3 id="常见的-bean-转换工具有哪些"><a href="#常见的-bean-转换工具有哪些" class="header-anchor">#</a> 常见的 Bean 转换工具有哪些？</h3> <p>推荐使用 <code>MapStruct</code>（编译时生成接口的实现类），<code>ModelMapper</code>（反射）。或者使用 Spring 提供的 <code>BeanUtils</code> 类（可能会有问题）。</p> <div class="custom-block warning"><p class="custom-block-title">不用使用 Apache 提供的 BeanUtils 类</p> <p>阿里编程规范不推荐使用 Apache 提供的 <code>BeanUtils</code> 类，因为存在性能问题（存在大量的校验和日志记录）。</p></div> <h3 id="beanfactory-和-factorybean-有哪些区别"><a href="#beanfactory-和-factorybean-有哪些区别" class="header-anchor">#</a> BeanFactory 和 FactoryBean 有哪些区别？</h3> <p><code>BeanFactory</code> 是接口，是 Spring 给 IoC 容器定义的一套完整的规范。<code>BeanFactory</code> 的实现类包括：</p> <ul><li><code>AbstractBeanFactory</code>：抽象 Bean 工厂，绝大部分的实现类都是继承于他</li> <li><code>DefaultListableBeanFactory</code>：Spring 默认的工厂类</li> <li><code>XmlBeanFactory</code>：早期使用 XML 文件配置时所使用的 Bean 工厂</li> <li><code>AbstractXmlApplicationContext</code>：抽象应用容器上下文对象</li> <li><code>ClassPathXmlApplicationContext</code>：XML 解析上下文对象</li></ul> <p><code>FactoryBean</code> 是 Spring IoC 容器创建 Bean 的一种形式，融合了简单工厂设计模式与装饰器模式。</p> <h3 id="spring-的三级缓存"><a href="#spring-的三级缓存" class="header-anchor">#</a> Spring 的三级缓存？<span class="badge error" style="vertical-align:top;" data-v-7b453e57>重点</span></h3> <p>在代码中有时可能会出现循环依赖，循环依赖是指是指 A 对象需要 B 对象，B 对象又需要 A 对象。比如下面这样：</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">A</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token class-name">B</span> b<span class="token punctuation">;</span>
 
    <span class="token keyword">public</span> <span class="token class-name">A</span><span class="token punctuation">(</span><span class="token class-name">B</span> b<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>b <span class="token operator">=</span> b<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
 
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">B</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token class-name">A</span> a<span class="token punctuation">;</span>
 
    <span class="token keyword">public</span> <span class="token class-name">B</span><span class="token punctuation">(</span><span class="token class-name">A</span> a<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>a <span class="token operator">=</span> a<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br></div></div><p>如果碰到这种情况，那么实例化时必然会陷入死循环，因此 Spring 使用三级缓存来解决循环依赖这一问题。</p> <ul><li><code>Map&lt;String, Object&gt; singletonObjects</code>：第一级缓存，用来存放已经完全创建好的单例 Bean，映射关系为 <code>beanName -&gt; Bean</code> 实例。</li> <li><code>Map&lt;String, Object&gt; earlySingletonObjects</code>：第二级缓存，用来存放半成品的 Bean，映射关系为 <code>beanName -&gt; Bean</code> 实例。</li> <li><code>Map&lt;String, ObjectFactory&lt;?&gt;&gt; singletonFactories</code>：第三级缓存，用来存放单例 Bean 的 <code>ObjectFactory</code>，映射关系为 <code>beanName -&gt; ObjectFactory</code> 实例。</li></ul> <p>还是以上面的 A 和 B 两个类为例，对创建过程详细的描述一下：</p> <ul><li>首先创建 A，此时三级缓存中都没有 A，将 A 扔到一个集合中，这个集合的名称叫做：<code>singletonsCurrentlyInCreation</code>，表示它们正处于创建状态</li> <li>对 A 做实例化，并放到第三级缓存中</li> <li>为 A 注入对象，发现需要 B</li> <li>从三级缓存中查找 B，发现都没有 B，将 B 放到 <code>singletonsCurrentlyInCreation</code> 中</li> <li>对 B 做实例化，并放到第三级缓存中</li> <li>为 B 注入对象，发现需要 A</li> <li>将 A 从第三级缓存移动到第二级缓存，并返回给 B 做填充，但此时 A 只是个半成品，它的属性还没有填充完</li> <li>B 创建完毕，从第三级缓存移动到第一级缓存</li> <li>将 B 返回给 A，A 将 B 填充，A 创建完成</li> <li>判断最后创建好的 A 和 B 中填充的 A 是不是一个对象，如果不是则抛出异常</li></ul> <h2 id="spring-事务"><a href="#spring-事务" class="header-anchor">#</a> Spring 事务</h2> <h3 id="管理事务的两种方式"><a href="#管理事务的两种方式" class="header-anchor">#</a> 管理事务的两种方式？</h3> <ul><li>编程式事务，在代码中硬编码（不推荐使用）</li> <li>声明式事务，在配置文件中配置（推荐使用），包括基于 XML 的声明式事务和基于注解的声明式事务</li></ul> <h3 id="事务隔离级别有哪些"><a href="#事务隔离级别有哪些" class="header-anchor">#</a> 事务隔离级别有哪些？</h3> <table><thead><tr><th style="text-align:center;">名称</th> <th style="text-align:center;">含义</th></tr></thead> <tbody><tr><td style="text-align:center;">TransactionDefinition.ISOLATION_DEFAULT</td> <td style="text-align:center;">使用后端数据库默认的隔离级别，MySQL 默认采用的 REPEATABLE_READ。</td></tr> <tr><td style="text-align:center;">TransactionDefinition.ISOLATION_READ_UNCOMMITTED</td> <td style="text-align:center;">最低的隔离级别，允许读取尚未提交的数据变更，可能会导致脏读、幻读和不可重复读。</td></tr> <tr><td style="text-align:center;">TransactionDefinition.ISOLATION_READ_COMMITTED</td> <td style="text-align:center;">允许读取并发事务已经提交的数据，可以阻止脏读，但是幻读和不可重复读仍有可能发生。</td></tr> <tr><td style="text-align:center;">TransactionDefinition.ISOLATION_REPEATABLE_READ</td> <td style="text-align:center;">对同一字段的多次读取结果都是一致的，除非数据是被本身事务自己所修改，可以阻止脏读和不可重复读，但幻读仍有可能发生。</td></tr> <tr><td style="text-align:center;">TransactionDefinition.ISOLATION_SERIALIZABLE</td> <td style="text-align:center;">最高的隔离级别，完全服从 ACID 的隔离级别。所有的事务依次逐个执行，这样事务之间就完全不可能产生干扰，也就是说该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。</td></tr></tbody></table> <h3 id="事务的传播方式有哪几种"><a href="#事务的传播方式有哪几种" class="header-anchor">#</a> 事务的传播方式有哪几种？</h3> <p>事务传播行为（Propagation Behavior）指的是当一个事务方法被另一个事务方法调用时，这个事务方法应该如何进行。例如：方法 A 调用方法 B 时，方法 B 是继续在调用者方法 A 的事务中运行，还是为自己开启一个新事务运行，这就是由方法 B 的事务传播行为决定的。</p> <p>Spring 支持以下 7 种事务传播方式：</p> <table><thead><tr><th style="text-align:center;">名称</th> <th style="text-align:center;">含义</th></tr></thead> <tbody><tr><td style="text-align:center;">PROPAGATION_REQUIRED</td> <td style="text-align:center;">如果当前存在事务，则加入该事务；如果当前没有事务，则创建一个新的事务</td></tr> <tr><td style="text-align:center;">PROPAGATION_SUPPORTS</td> <td style="text-align:center;">如果当前存在事务，则加入该事务；如果当前没有事务，则以非事务的方式继续运行</td></tr> <tr><td style="text-align:center;">PROPAGATION_MANDATORY</td> <td style="text-align:center;">如果当前存在事务，则加入该事务；如果当前没有事务，则抛出异常</td></tr> <tr><td style="text-align:center;">PROPAGATION_REQUIRES_NEW</td> <td style="text-align:center;">创建一个新的事务，如果当前存在事务，则把当前事务挂起</td></tr> <tr><td style="text-align:center;">PROPAGATION_NOT_SUPPORTED</td> <td style="text-align:center;">以非事务方式运行，如果当前存在事务，则把当前事务挂起</td></tr> <tr><td style="text-align:center;">PROPAGATION_NEVER</td> <td style="text-align:center;">以非事务方式运行，如果当前存在事务，则抛出异常</td></tr> <tr><td style="text-align:center;">PROPAGATION_NESTED</td> <td style="text-align:center;">如果当前存在事务，则创建一个事务作为当前事务的嵌套事务来运行；如果当前没有事务，则该取值等价于 PROPAGATION_REQUIRED</td></tr></tbody></table> <h3 id="哪些方法可以开启事务"><a href="#哪些方法可以开启事务" class="header-anchor">#</a> 哪些方法可以开启事务？</h3> <p>当 <code>@Transactional</code> 注解作用于类上时，该类的所有 <code>public</code> 方法将都具有该类型的事务属性，可以在方法上再次使用该标注来覆盖类级别的定义。如果类或者方法加了这个注解，那么这个类里面的方法抛出异常，就会导致回滚。</p> <h3 id="什么情况下会导致事务回滚"><a href="#什么情况下会导致事务回滚" class="header-anchor">#</a> 什么情况下会导致事务回滚？</h3> <p>在 <code>@Transactional</code> 注解中如果不配置 <code>rollbackFor</code> 属性，那么事务只会在遇到 <code>RuntimeException</code> 的时候才会回滚，加上 <code>rollbackFor=Exception.class</code> 可以让事务在遇到非运行时异常时也回滚。</p> <h3 id="在什么场景下会导致事务失效"><a href="#在什么场景下会导致事务失效" class="header-anchor">#</a> 在什么场景下会导致事务失效？</h3> <ul><li>数据库引擎不支持事务，比如 MyISAM</li> <li>使用 <code>@Transactional</code> 标注的类没有被 Spring 容器管理</li> <li>方法的修饰符不是 <code>public</code></li> <li>自调用问题</li> <li>数据源没有配置事务管理器</li> <li>事务传播级别为：<code>PROPAGATION_NOT_SUPPORTED</code></li> <li>没有添加 <code>rollbackFor=Exception.class</code></li> <li>使用 <code>try-catch</code> 语句对异常进行了捕获，但没有重新抛出运行时异常</li></ul> <div class="custom-block tip"><p class="custom-block-title">什么是自调用</p> <p>自调用是指在类 A 里面有方法 a 和方法 b， 在方法 b 上面添加了 <code>@Transactional</code> 注解，在方法 a 中调用方法 b， 方法 b 的事务是不会生效的。原因在于同一个类之中，方法互相调用导致切面无效，而不仅仅是事务。事务之所以无效，是因为 Spring 的事务是通过 AOP 实现的。</p></div></div> <!----> <div class="content__content-bottom"></div> <footer class="page-meta"><div class="edit-link"><svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" class="icon edit-icon"><path d="M117.953 696.992 64.306 959.696l265.931-49.336 450.204-452.505-212.284-213.376-450.204 452.513zm496.384-296.326L219.039 797.993l-46.108-46.34L568.233 354.33l46.104 46.335zm345.357-122.99-114.45 115.04-212.288-213.377 114.45-115.035 212.288 213.371zm0 0" fill="currentColor"></path></svg> <a href="https://github.com/lxy1152/lxy1152.github.io/edit/main/interview/framework/spring/spring.md" target="_blank" rel="noopener noreferrer">编辑此页</a></div> <div class="meta-item update-time"><span class="label">上次编辑于:</span> <span class="info">2021年8月1日 19:23</span></div> <div class="meta-item contributors"><span class="label">贡献者: </span> <span class="info"><span title="email: 2676092082@qq.com" class="contributor">
          Xiangyu Li
        </span> <!----></span></div></footer> <div class="page-nav"><p class="inner"><span class="prev"><a href="/interview/framework/spring/" class="prev router-link-active"><svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" class="icon prev-icon"><path d="M906.783 588.79c-.02 8.499-6.882 15.36-15.38 15.37l-443.7-.01 75.704 191.682c2.52 6.42.482 13.763-5.038 17.91-5.52 4.168-13.138 4.147-18.616-.092L123.228 524.175a15.362 15.362 0 0 1-6-12.165c0-4.782 2.222-9.277 6-12.185L499.753 210.35a15.388 15.388 0 0 1 9.38-3.195c3.236 0 6.502 1.034 9.236 3.103 5.52 4.147 7.578 11.49 5.038 17.91L447.683 419.84l443.72-.01c8.498.01 15.36 6.881 15.36 15.36l.02 153.6z" fill="currentColor"></path></svg>
        💐 Spring 全家桶 - 简介
      </a></span> <span class="next"><a href="/interview/framework/spring/spring-mvc/">
        🌳 SpringMVC
        <svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" class="icon next-icon"><path d="M906.772 512c0 4.772-2.211 9.267-5.99 12.175L524.257 813.66a15.37 15.37 0 0 1-18.616.092 15.368 15.368 0 0 1-5.038-17.91l75.714-191.672h-443.73c-8.488 0-15.36-6.881-15.36-15.36v-153.6c0-8.489 6.872-15.36 15.36-15.36h443.73l-75.714-191.682a15.358 15.358 0 0 1 5.048-17.91c5.51-4.158 13.128-4.137 18.606.092l376.525 289.485a15.323 15.323 0 0 1 5.99 12.165z" fill="currentColor"></path></svg></a></span></p></div> <div class="comments-wrapper"><div class="waline-wrapper"><div id="waline-comment"></div></div></div> <!----> <div class="content__page-bottom"></div></main> <footer class="footer-wrapper"><!----> <!----> <div class="copyright">Copyright © 2021 Xiangyu Li</div></footer></div><div class="global-ui"><!----><div tabindex="-1" role="dialog" aria-hidden="true" class="pswp"><div class="pswp__bg"></div> <div class="pswp__scroll-wrap"><div class="pswp__container"><div class="pswp__item"></div> <div class="pswp__item"></div> <div class="pswp__item"></div></div> <div class="pswp__ui pswp__ui--hidden"><div class="pswp__top-bar"><div class="pswp__counter"></div> <button class="pswp__button pswp__button--close"></button> <button class="pswp__button pswp__button--share"></button> <button class="pswp__button pswp__button--fs"></button> <button class="pswp__button pswp__button--zoom"></button> <div class="pswp__preloader"><div class="pswp__preloader__icn"><div class="pswp__preloader__cut"><div class="pswp__preloader__donut"></div></div></div></div></div> <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap"><div class="pswp__share-tooltip"></div></div> <button class="pswp__button pswp__button--arrow--left"></button> <button class="pswp__button pswp__button--arrow--right"></button> <div class="pswp__caption"><div class="pswp__caption__center"></div></div></div></div></div></div></div>
    <script src="/assets/js/app.a42375e9.js" defer></script><script src="/assets/js/vendors~layout-Layout.8269724e.js" defer></script><script src="/assets/js/vendors~layout-Blog~layout-Layout~layout-NotFound.43b0f70d.js" defer></script><script src="/assets/js/page-🌲Spring.bc450c2f.js" defer></script><script src="/assets/js/vendors~layout-Blog~layout-Layout~layout-NotFound~layout-Slide.99c28334.js" defer></script>
  </body>
</html>
